/*
 * Copyright (C) 2011 Niels Mayer <NielsMayer _AT_ gmail _DOT_ com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <QtGui/QApplication>
#include <QDeclarativeContext>
#include <QtDeclarative>
#include <QDeclarativeNetworkAccessManagerFactory>
#include <QStringList>
#include "qmlapplicationviewer.h"
#include <QtOpenGL/QGLWidget>	// needed for viewer.setViewport(new QGLWidget()) below.
#include <QtOpenGL/QGLFormat>

// NPM: HACK/WORKAROUND FOR QT 4.7. Need to setup networking to not puke on
// SSL errors, which prevented Bugzibit example from working with
// https://bugs.meego.com due to its SSL implementation and certificate.
// This workaround will not be necessary at some point per Thiago's comment
// "QSslSocket does not send the Server Name Identification SSL extension
// [in Qt 4.7] ... QSslSocket in Qt 4.8 does send SNI now."  (
// http://lists.meego.com/pipermail/meego-dev/2011-May/482965.html
// http://lists.meego.com/pipermail/meego-dev/2011-May/482968.html ). For
// details on technique, see
// http://www.developer.nokia.com/Community/Wiki/Why_does_QML_require_QDeclarativeNetworkAccessManagerFactory
// http://www.qtcentre.org/threads/21470-SSL-Problem
class MyNetworkAccessManager : public QNetworkAccessManager {
public:
  MyNetworkAccessManager ();
  MyNetworkAccessManager (QObject *parent);

protected:
  QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0);
};

MyNetworkAccessManager::MyNetworkAccessManager () {
}
MyNetworkAccessManager::MyNetworkAccessManager (QObject *parent) {
}
QNetworkReply *MyNetworkAccessManager::createRequest ( Operation op, const QNetworkRequest &req, QIODevice *outgoingData ) {
    QSslConfiguration config = req.sslConfiguration();
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1);
    QNetworkRequest request(req);
    request.setSslConfiguration(config);
    return QNetworkAccessManager::createRequest(op, request, outgoingData);
    //NPM: Alternative implementation, which is more of a hack?
    //QNetworkReply* reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
    //reply->ignoreSslErrors();
    //return reply;
}

class MyNetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory {
public:
    virtual QNetworkAccessManager *create(QObject *parent);
};
QNetworkAccessManager *MyNetworkAccessManagerFactory::create(QObject *parent) {
    QNetworkAccessManager *nam = new MyNetworkAccessManager(parent); // NPM:
    qDebug() << "DEBUG: MyNetworkAccessManagerFactory::create()'d nam=" << nam;
//    if (!proxyHost.isEmpty()) {
//        qDebug() << "DEBUG: Created QNetworkAccessManager using proxy" << (proxyHost + ":" + QString::number(proxyPort));
//        QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, proxyHost, proxyPort);
//        nam->setProxy(proxy);
//    }
    return nam;
}

int main(int argc, char *argv[]) {
  bool         commandlineURL_mode	= false; //NPM
  QString      commandlineURL		= NULL;  //NPM
  bool         opengl_mode		= true;	 //NPM
  QApplication app(argc, argv);   

#ifdef Q_WS_X11		// NPM: aka, MeeGo 
  // NPM: unless '--raster' command-line option given, this gets
  // overriden by using viewer.setViewport(new QGLWidget()) below
  QApplication::setGraphicsSystem(QString::fromLatin1("raster"));
#endif	/* defined(Q_WS_X11) */
#ifdef MEEGO_EDITION_HARMATTAN
  QApplication::setFont(QFont("Nokia Pure Text", 16));
#endif  /* defined(MEEGO_EDITION_HARMATTAN) */

  QApplication::setApplicationName(QString("qtzibit"));

  QStringList arglist = app.arguments();
  arglist.takeFirst();
  if (!arglist.isEmpty()) {
    QString car = arglist.first();

    if (car == "--raster") {
      opengl_mode = false;
      arglist.takeFirst();
      if (!arglist.isEmpty()) {
	car = arglist.first();
      }
    }

    if (car == "--url") {
      commandlineURL_mode = true;
      arglist.takeFirst();
      if (!arglist.isEmpty()) {
	commandlineURL = arglist.first();
	arglist.takeFirst();
      }
      else {
	qWarning() << "qtzibit: missing --url argument";
	exit(1);
      }
    }
    else if (!arglist.isEmpty()) {
      qWarning() << "Error: Unexpected commandline arguments. Usage: qtzibit [[--raster] --url <file>]";
      exit(1);
    }

    if (!arglist.isEmpty() && (!opengl_mode || commandlineURL_mode)) {
      qWarning() << "Error: Too many commandline arguments. Usage: qtzibit [[--raster] --url <file>]";
      exit(1);
    }
  }

  QmlApplicationViewer viewer;
  viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
  viewer.setAttribute(Qt::WA_NoSystemBackground);
  
  /* when '--url' commandline given, pass argument to qml as 'commandlineURL' */
  QDeclarativeContext *context = viewer.rootContext();
  if (commandlineURL_mode) {
    qDebug() << "DEBUG: commandlineURL =" << commandlineURL;
    context->setContextProperty("commandlineURL", commandlineURL);
  }
  else {
    context->setContextProperty("commandlineURL", QString("")); //easier than trying to figure out how to pass null
  }

  if (opengl_mode) {
    // NPM: trying to understand what these all do as suggested by
    // http://doc.qt.nokia.com/latest/qt-embeddedlinux-opengl.html
    // and http://meego.gitorious.org/meego-ux/meego-qml-launcher/blobs/master/src/launcherwindow.cpp#line355
    // --> LauncherWindow::doSwitchToGLRendering()
    //
    // http://doc.qt.nokia.com/latest/qglformat.html#defaultFormat
    // "Returns the default QGLFormat for the application. All QGLWidget objects that are created use this format unless another format is specified, e.g. when they are constructed."
    QGLFormat format = QGLFormat::defaultFormat();
    // http://doc.qt.nokia.com/latest/qglformat.html#setSampleBuffers
    // "If enable is true, a GL context with multisample buffer support is picked; otherwise ignored."
    format.setSampleBuffers(false);
    // http://doc.qt.nokia.com/latest/qglwidget.html#QGLWidget-3
    // "The format argument specifies the desired rendering options. If the underlying OpenGL/Window system cannot satisfy all the features requested in format, the nearest subset of features will be used. After creation, the format() method will return the actual format obtained. The widget will be invalid if the system has no OpenGL support."
    QGLWidget* glw = new QGLWidget(format);
    if (glw->isValid()) {
      viewer.setViewport(glw);
      // http://doc.qt.nokia.com/latest/qabstractscrollarea.html#setHorizontalScrollBarPolicy
      viewer.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
      // http://doc.qt.nokia.com/latest/qabstractscrollarea.html#verticalScrollBarPolicy-prop
      viewer.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
      // http://doc.qt.nokia.com/latest/qgraphicsview.html#ViewportUpdateMode-enum
      // "When any visible part of the scene changes or is reexposed, QGraphicsView will update the entire viewport. This approach is fastest when QGraphicsView spends more time figuring out what to draw than it would spend drawing (e.g., when very many small items are repeatedly updated). This is the preferred update mode for viewports that do not support partial updates, such as QGLWidget, and for viewports that need to disable scroll optimization."
      viewer.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);

      // http://doc.qt.nokia.com/latest/qt.html#WidgetAttribute-enum
      // Qt::WA_OpaquePaintEvent -- "The use of WA_OpaquePaintEvent provides a small optimization by helping to reduce flicker on systems that do not support double buffering and avoiding computational cycles necessary to erase the background prior to painting. Note: Unlike WA_NoSystemBackground, WA_OpaquePaintEvent makes an effort to avoid transparent window backgrounds. This flag is set or cleared by the widget's author."
      viewer.viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
      // http://doc.qt.nokia.com/latest/qt.html#WidgetAttribute-enum
      // Qt::WA_NoSystemBackground -- "Indicates that the widget has no background, i.e. when the widget receives paint events, the background is not automatically repainted. Note: Unlike WA_OpaquePaintEvent, newly exposed areas are never filled with the background (e.g., after showing a window for the first time the user can see "through" it until the application processes the paint events). This flag is set or cleared by the widget's author."
      viewer.viewport()->setAttribute(Qt::WA_NoSystemBackground);
      // http://doc.qt.nokia.com/latest/qframe.html#setFrameStyle
      viewer.setFrameStyle(QFrame::NoFrame); //QFrame draws nothing
    }
    else {
      qWarning() << "Unable to create QGLWidget: suggest trying '--raster' command-line option.";
    }
  }
  
  // Setup any QML-invoked networking to not puke on SSL errors, which prevented QML WebKit invoked
  // Bugzibit example from working with https://bugs.meego.com due to its SSL implementation and certificate.
  // suggested by http://www.developer.nokia.com/Community/Wiki/Why_does_QML_require_QDeclarativeNetworkAccessManagerFactory
  viewer.engine()->setNetworkAccessManagerFactory(new MyNetworkAccessManagerFactory); 

  // Even though Harmattan has /home/user/MyDocs it appears other apps store
  // local info in /home/user, e.g. /home/user/.qcamera /home/user/.facebook etc.
  // thus leave configuration directory location same for both MeeGo and Harmattan
  viewer.engine()->setOfflineStoragePath(QDir::homePath() + "/.config/qtzibit");
  QDir path;
  path.setPath(QDir::homePath() + "/.config/qtzibit");
  if (!path.exists()) {
    path.mkpath(QDir::homePath() + "/.config/qtzibit");
  }

  viewer.setMainQmlFile(QLatin1String("qml/main.qml"));

  /* NPM: the following sequence of ifdefs was viewer.showExpanded()
     but it didn't do right thing on Harmattan, so replaced with ifdefs
     below.... see: http://forum.meego.com/showthread.php?p=27001 
     "Patch to get rid of "gray bar" in QtCreator's qmlapplicationviewer" .
  */
#ifdef Q_OS_SYMBIAN
  viewer.showFullScreen();
#elif defined(Q_WS_MAEMO_5)
  viewer.showMaximized();
#elif defined(MEEGO_EDITION_HARMATTAN)
  viewer.showFullScreen();
#elif defined(Q_WS_MEEGO)
  viewer.showMaximized();
#else // desktop linux, meego netbook/tablet, etc.
  viewer.show();
#endif

  return app.exec();
}
